import Tag from "../Tag";
import Popover, { PopoverProps } from "../Popover";
import { PropType, computed, defineComponent, onBeforeUnmount, onMounted, reactive, ref, watch, watchEffect } from "vue";
import { uuidv4 } from "../utils/assist";

export interface TagConfig {
    id: string|number
    title: string
    theme?: 'primary'|'danger'|'warning'|'success'|'info'|'magenta'|'red'|'volcano'|'orange'|'gold'|'yellow'|'lime'|'green'|'cyan'|'blue'|'geekblue'|'purple',
    avatar?: any
    [key: string]: any
}

export interface TagGroupProps {
    data: TagConfig[]
    closable?: boolean
    max?: number | 'auto'
    showMore?: boolean,
    moreCloseable?: boolean
    tooltipAlign?: PopoverProps['align'],
    tooltipTheme?: PopoverProps['color'],
    tooltipTrigger?: PopoverProps['trigger'],
    tooltipStyle?: PopoverProps['style'],
    size?: 'small'|'large'|'xlarge'
    extra?: any
    onClose? (item: TagConfig, e: any): void
}

export default defineComponent({
    name: 'TagGroup',
    props: {
        data: { type: Array as PropType<TagGroupProps['data']>, default: [] },
        closable: { type: Boolean as PropType<TagGroupProps['closable']>, default: false },
        max: { type: [Number, String] as PropType<TagGroupProps['max']>},
        showMore: { type: Boolean as PropType<TagGroupProps['showMore']>, default: false},
        moreCloseable: { type: Boolean as PropType<TagGroupProps['moreCloseable']>},
        tooltipAlign: { type: String as PropType<TagGroupProps['tooltipAlign']>, default: 'top' },
        tooltipTheme: { type: String as PropType<TagGroupProps['tooltipTheme']>, default: 'light' },
        tooltipTrigger: { type: String as PropType<TagGroupProps['tooltipTrigger']>, default: 'hover' },
        tooltipStyle: { type: Object as PropType<TagGroupProps['tooltipStyle']> },
        size: { type: String as PropType<TagGroupProps['size']>, default: 'small'},
        extra: { type: Object as PropType<TagGroupProps['extra']>},
    },
    emits: ['close'],
    setup (props: TagGroupProps, { emit }) {
        const classList = computed(() => ({
            'cm-tag-group': true,
            'cm-tag-group-overflow': props.max === 'auto',
        }));
        const wrap = ref();
        const showStyle = {
            position: '',
            height: '',
            'point-event': '',
            overflow: ''
        };

        const hideStyle = {
            position: 'absolute',
            height: '0px',
            'point-event': 'none',
            overflow: 'hidden'
        };

        const store = reactive({
            list: [],
            show: [],
            hide: []
        } as {list: TagConfig[], show: TagConfig[], hide: TagConfig[]});

        const onClose = (item: TagConfig, e: any) => {
            const newList = store.list.filter(aitem => {
                return aitem.id !== item.id;
            });
            store.list = newList;
            emit('close', e);
            queueMicrotask(() => {
                onSizeChange();
            });
        };

        watchEffect(() => {
            const arr = props.data.map((item: any) => {
                if (item.id === undefined) {
                    item.id = uuidv4();
                }
                if (props.max === 'auto') {
                    item._style = {...hideStyle};
                }
                return item;
            });
            store.list = arr;

            const show:TagConfig[] = [];
            const hide:TagConfig[] = [];

            if (props.max === 'auto') {
                store.hide = hide;
                queueMicrotask(() => {
                    onSizeChange();
                });
            } else {
                const max = props.max ?? arr.length;
                for (let i = 0; i < max; i++) {
                    arr[i] && show.push(arr[i]);
                }
                const length = arr.length;
                for (let j = max; j < length; j++) {
                    hide.push(arr[j]);
                }
                store.show = show;
                store.hide = hide;
            }
        });

        // watch(() => store.list, (list: TagConfig[]) => {
        //     console.log(222);

        // });

        // 隐藏
        const hideTag = (index: number) => {
            if (!store.hide.includes(store.list[index])) {
                store.hide.push(store.list[index]);
            }
            // store.list[index]._style = {...hideStyle};
        };

        // 显示
        const showTag = (index: number) => {
            // 已经隐藏的从hide中移除
            const idx = store.hide.indexOf(store.list[index]);
            if (idx > -1) {
                store.hide.splice(idx, 1);
            }
            // store.list[index]._style = {...showStyle};
        };

        const onSizeChange = () => {
            if (props.max !== 'auto') {
                return;
            }
            const wrapRect = wrap.value.getBoundingClientRect();
            const tags: any[] = wrap.value.querySelectorAll('.cm-tag:not(.cm-tag-more)');
            let w = 0;

            const more = wrap.value.querySelector('.cm-tag-more');
            const shows: number[] = [];
            const hides: number[] = [];
            tags.forEach((tag, index) => {
                const moreRect = more?.getBoundingClientRect();
                const moreWidth = moreRect ? 5 + moreRect?.width : 25;
                const tagWidth = tag.offsetWidth;
                if (w + (index === 0 ? 0 : 5) + tagWidth + moreWidth < wrapRect.width) {
                    w = w + (index === 0 ? 0 : 5) + tagWidth;
                    if (tag.style.height === '0px') {
                        shows.push(index);
                    }
                } else {
                    hides.push(index);
                }
            });
            // 批量修改
            shows.forEach(index => {
                showTag(index);
            });
            hides.forEach(index => {
                hideTag(index);
            });
        };

        onMounted(() => {
            const ob = new ResizeObserver(() => {
                onSizeChange();
            });
            if (props.max === 'auto') {
                ob.observe(wrap.value);
            }

            onBeforeUnmount(() => {
                ob.disconnect();
            });
        });

        return () => <div class={classList.value} ref={wrap}>
            {
                props.max === 'auto'
                    ? store.list.map(item => {
                        return <Tag closable={props.closable} style={store.hide.indexOf(item) > -1 ? hideStyle : showStyle } size={props.size} theme={item.theme} avatar={item.avatar} onClose={(e: any) => {
                            onClose(item, e);
                        }}>{item.title}</Tag>;
                    })
                    : store.show.map(item => {
                        return <Tag closable={props.closable} size={props.size} theme={item.theme} avatar={item.avatar} onClose={(e: any) => {
                            onClose(item, e);
                        }}>{item.title}</Tag>;
                    })
            }
            {
                store.hide.length
                    ? (props.showMore ? <Popover class="cm-tag-group-more-popover" align={props.tooltipAlign} arrow
                        theme={props.tooltipTheme} trigger={props.tooltipTrigger} style={props.tooltipStyle} content={
                            <div class="cm-tag-group-more-wrap">
                                {
                                    store.hide.map((item: TagConfig) => {
                                        return <Tag size={props.size} theme={item.theme} closable={props.moreCloseable} onClose={(e: any) => {
                                            onClose(item, e);
                                        }}
                                        avatar={item.avatar}>{item.title}</Tag>;
                                    })
                                }
                            </div>
                        }>
                        <Tag class="cm-tag-more"><span>+</span>{store.hide.length}</Tag>
                    </Popover>
                        : <Tag class="cm-tag-more"><span>+</span>{store.hide.length}</Tag>
                    )
                    : null
            }
            { props.extra }
        </div>;
    }
});
